package org.chen.aao.user.service;

import org.chen.aao.common.exception.BusinessException;
import org.chen.aao.common.user.dto.*;
import org.chen.aao.common.user.e.CodeType;
import org.chen.aao.user.service.email.VerificationCodeService;
import org.chen.aao.user.utils.JwtUtil;
import org.chen.aao.common.user.entity.User;
import org.chen.aao.user.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {
    
    private final UserMapper userMapper;
    private final JwtUtil jwtUtil;
    private final RedisTemplate<String, Object> redisTemplate;
    private final VerificationCodeService verificationCodeService;
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    /**
     * 用户注册（带验证码）
     */
    @Transactional
    public RegisterResponse register(RegisterRequest request) {
        // 验证邮箱格式
        if (isValidEmail(request.getEmail())) {
            throw new BusinessException("邮箱格式不正确");
        }

        // 检查邮箱是否已存在
        User existingUser = userMapper.selectOne(
                new QueryWrapper<User>().eq("email", request.getEmail())
        );

        if (existingUser != null) {
            throw new BusinessException("该邮箱已被注册");
        }

        // 验证验证码（如果提供了验证码）
        if (StringUtils.hasText(request.getVerificationCode())) {
            boolean isValidCode = verificationCodeService.verifyCode(
                    request.getEmail(),
                    request.getVerificationCode(),
                    CodeType.REGISTER
            );

            if (!isValidCode) {
                throw new BusinessException(506, "验证码错误或已过期");
            }
        }

        // 创建新用户
        User user = new User();
        user.setEmail(request.getEmail());
        user.setUsername(request.getUsername());
        user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
        user.setStatus("ACTIVE");
        user.setEmailVerified(StringUtils.hasText(request.getVerificationCode()));

        userMapper.insert(user);

        // 生成token
        String token = jwtUtil.generateToken(user.getId(), user.getEmail());
        String refreshToken = jwtUtil.generateRefreshToken(user.getId());

        // 缓存用户信息
        cacheUserInfo(user);

        log.info("用户注册成功: userId={}, email={}", user.getId(), user.getEmail());

        return RegisterResponse.builder()
                .userId(user.getId())
                .email(user.getEmail())
                .username(user.getUsername())
                .token(token)
                .refreshToken(refreshToken)
                .build();
    }

    /**
     * 发送注册验证码
     */
    public void sendRegisterCode(SendCodeRequest request) {
        String email = request.getEmail();

        // 验证邮箱格式
        if (isValidEmail(email)) {
            throw new BusinessException("邮箱格式不正确");
        }

        // 检查邮箱是否已注册
        User existingUser = userMapper.selectOne(
                new QueryWrapper<User>().eq("email", email)
        );

        if (existingUser != null) {
            throw new BusinessException("该邮箱已被注册");
        }

        // 发送验证码
        verificationCodeService.sendVerificationCode(email, CodeType.REGISTER);
    }

    /**
     * 发送密码重置验证码
     */
    public void sendResetPasswordCode(SendCodeRequest request) {
        String email = request.getEmail();

        // 验证邮箱格式
        if (isValidEmail(email)) {
            throw new BusinessException("邮箱格式不正确");
        }

        // 检查用户是否存在
        User user = userMapper.selectOne(
                new QueryWrapper<User>().eq("email", email)
        );

        if (user == null) {
            throw new BusinessException("该邮箱未注册");
        }

        // 发送验证码
        verificationCodeService.sendVerificationCode(email, CodeType.RESET_PASSWORD);
    }

    /**
     * 重置密码
     */
    @Transactional
    public void resetPassword(ResetPasswordRequest request) {
        // 验证验证码
        boolean isValidCode = verificationCodeService.verifyCode(
                request.getEmail(),
                request.getCode(),
                CodeType.RESET_PASSWORD
        );

        if (!isValidCode) {
            throw new BusinessException("验证码错误或已过期");
        }

        // 查询用户
        User user = userMapper.selectOne(
                new QueryWrapper<User>().eq("email", request.getEmail())
        );

        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 更新密码
        user.setPasswordHash(passwordEncoder.encode(request.getNewPassword()));
        userMapper.updateById(user);

        // 清除所有token缓存，强制重新登录
        clearUserTokens(user.getId());

        log.info("密码重置成功: userId={}, email={}", user.getId(), user.getEmail());
    }

    public LoginResponse login(LoginRequest request) {
        // 查询用户
        User user = userMapper.selectOne(
            new QueryWrapper<User>().eq("email", request.getEmail())
        );
        
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 验证密码
        if (!passwordEncoder.matches(request.getPassword(), user.getPasswordHash())) {
            throw new BusinessException("密码错误");
        }
        
        // 检查用户状态
        if (!"ACTIVE".equals(user.getStatus())) {
            throw new BusinessException("账号已被禁用");
        }
        
        // 生成token
        String token = jwtUtil.generateToken(user.getId(), user.getEmail());
        
        // 缓存用户信息
        cacheUserInfo(user);
        
        // 记录登录日志
        recordLoginLog(user.getId(), request.getDeviceInfo());
        
        return LoginResponse.builder()
                .userId(user.getId())
                .email(user.getEmail())
                .username(user.getUsername())
                .avatarUrl(user.getAvatarUrl())
                .token(token)
                .build();
    }
    
    public UserInfoResponse getUserInfo(Long userId) {
        String cacheKey = "user:info:" + userId;
        UserInfoResponse cached = (UserInfoResponse) redisTemplate.opsForValue().get(cacheKey);
        
        if (cached != null) {
            return cached;
        }
        
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        UserInfoResponse response = UserInfoResponse.builder()
                .userId(user.getId())
                .email(user.getEmail())
                .username(user.getUsername())
                .avatarUrl(user.getAvatarUrl())
                .createdAt(user.getCreatedAt())
                .build();
        
        redisTemplate.opsForValue().set(cacheKey, response, 1, TimeUnit.HOURS);
        
        return response;
    }
    
    @Transactional
    public UserInfoResponse updateProfile(Long userId, UpdateProfileRequest request) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        if (StringUtils.hasText(request.getUsername())) {
            // 检查用户名是否被占用
            User existingUser = userMapper.selectOne(
                    new QueryWrapper<User>()
                            .eq("username", request.getUsername())
                            .ne("id", userId)
            );
            if (existingUser != null) {
                throw new BusinessException("用户名已被使用");
            }
            user.setUsername(request.getUsername());
        }

        if (StringUtils.hasText(request.getAvatarUrl())) {
            user.setAvatarUrl(request.getAvatarUrl());
        }

        userMapper.updateById(user);

        // 清除缓存
        String cacheKey = "user:info:" + userId;
        redisTemplate.delete(cacheKey);

        // 返回更新后的用户信息
        return getUserInfo(userId);
    }
    
    @Transactional
    public void changePassword(Long userId, ChangePasswordRequest request) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 验证旧密码
        if (!passwordEncoder.matches(request.getOldPassword(), user.getPasswordHash())) {
            throw new BusinessException("原密码错误");
        }
        
        // 更新密码
        user.setPasswordHash(passwordEncoder.encode(request.getNewPassword()));
        userMapper.updateById(user);
        
        // 清除所有token缓存，强制重新登录
        clearUserTokens(userId);

        log.info("密码修改成功: userId={}", userId);
    }

    /**
     * 验证邮箱格式
     */
    private boolean isValidEmail(String email) {
        if (!StringUtils.hasText(email)) {
            return true;
        }
        String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@" +
                "(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
        return !email.matches(emailRegex);
    }

    private void cacheUserInfo(User user) {
        String cacheKey = "user:info:" + user.getId();
        UserInfoResponse info = UserInfoResponse.builder()
                .userId(user.getId())
                .email(user.getEmail())
                .username(user.getUsername())
                .avatarUrl(user.getAvatarUrl())
                .createdAt(user.getCreatedAt())
                .build();
        
        redisTemplate.opsForValue().set(cacheKey, info, 1, TimeUnit.HOURS);
    }
    
    private void recordLoginLog(Long userId, String deviceInfo) {
        // 记录登录日志到Redis或数据库
        String logKey = "login:log:" + userId;
        redisTemplate.opsForList().leftPush(logKey, deviceInfo + ":" + System.currentTimeMillis());
        redisTemplate.expire(logKey, 30, TimeUnit.DAYS);
    }
    
    private void clearUserTokens(Long userId) {
        // 实际项目中应该维护token黑名单
        String pattern = "token:*:" + userId;
        redisTemplate.delete(redisTemplate.keys(pattern));
    }

    /**
     * 刷新Token
     */
    public RefreshTokenResponse refreshToken(RefreshTokenRequest request) {
        String refreshToken = request.getRefreshToken();

        // 验证刷新Token
        if (!jwtUtil.validateToken(refreshToken)) {
            throw new BusinessException("刷新Token无效或已过期");
        }

        // 检查是否为刷新Token类型
        if (!jwtUtil.isRefreshToken(refreshToken)) {
            throw new BusinessException("Token类型错误");
        }

        // 提取用户ID
        Long userId = jwtUtil.getUserIdFromToken(refreshToken);

        // 检查刷新Token是否在黑名单中
        String tokenId = jwtUtil.extractTokenId(refreshToken);
        if (tokenId != null && isTokenBlacklisted(tokenId)) {
            throw new BusinessException("刷新Token已失效");
        }

        // 查询用户信息
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 检查用户状态
        if (!"ACTIVE".equals(user.getStatus())) {
            throw new BusinessException("账号已被禁用");
        }

        // 生成新的访问Token
        String newAccessToken = jwtUtil.generateToken(userId, user.getEmail());

        // 判断是否需要生成新的刷新Token（如果旧的快过期了）
        String newRefreshToken = refreshToken;
        long remainingTime = jwtUtil.getTokenRemainingTime(refreshToken);
        if (remainingTime < 86400) { // 少于1天时生成新的
            // 将旧的刷新Token加入黑名单
            if (tokenId != null) {
                addTokenToBlacklist(tokenId, remainingTime);
            }
            newRefreshToken = jwtUtil.generateRefreshToken(userId);
        }

        log.info("Token刷新成功: userId={}", userId);

        return RefreshTokenResponse.builder()
                .token(newAccessToken)
                .refreshToken(newRefreshToken)
                .build();
    }

    /**
     * 用户登出
     */
    public void logout(Long userId) {
        try {
            // 清除用户缓存
            String cacheKey = "user:info:" + userId;
            redisTemplate.delete(cacheKey);

            // 清除用户的所有活动Token（可选，根据业务需求）
            clearUserTokens(userId);

            // 记录登出日志
            String logKey = "logout:log:" + userId;
            String logEntry = String.format("%d|logout", System.currentTimeMillis());
            redisTemplate.opsForList().leftPush(logKey, logEntry);
            redisTemplate.expire(logKey, 30, TimeUnit.DAYS);

            log.info("用户登出成功: userId={}", userId);
        } catch (Exception e) {
            log.error("用户登出失败: userId={}, error={}", userId, e.getMessage());
            // 登出失败不抛出异常，确保客户端可以正常清理本地存储
        }
    }

    /**
     * 检查Token是否在黑名单中
     */
    private boolean isTokenBlacklisted(String tokenId) {
        String blacklistKey = "token:blacklist:" + tokenId;
        return redisTemplate.hasKey(blacklistKey);
    }

    /**
     * 将Token加入黑名单
     */
    private void addTokenToBlacklist(String tokenId, long ttlSeconds) {
        String blacklistKey = "token:blacklist:" + tokenId;
        redisTemplate.opsForValue().set(blacklistKey, "1", ttlSeconds, TimeUnit.SECONDS);
    }

    /**
     * 验证邮箱
     */
    @Transactional
    public void verifyEmail(String email, String code) {
        // 验证验证码
        boolean isValidCode = verificationCodeService.verifyCode(
                email,
                code,
                CodeType.BIND_EMAIL
        );

        if (!isValidCode) {
            throw new BusinessException("验证码错误或已过期");
        }

        // 查询并更新用户
        User user = userMapper.selectOne(
                new QueryWrapper<User>().eq("email", email)
        );

        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        user.setEmailVerified(true);
        user.setEmailVerifiedAt(LocalDateTime.now());
        userMapper.updateById(user);

        // 清除缓存
        String cacheKey = "user:info:" + user.getId();
        redisTemplate.delete(cacheKey);

        log.info("邮箱验证成功: userId={}, email={}", user.getId(), email);
    }

    /**
     * 获取用户登录历史
     */
    public List<LoginHistoryDTO> getLoginHistory(Long userId) {
        String logKey = "login:log:" + userId;
        List<Object> logs = redisTemplate.opsForList().range(logKey, 0, 19); // 获取最近20条

        if (logs == null || logs.isEmpty()) {
            return new ArrayList<>();
        }

        return logs.stream()
                .map(log -> {
                    String logStr = (String) log;
                    String[] parts = logStr.split("\\|");
                    LoginHistoryDTO history = new LoginHistoryDTO();
                    if (parts.length >= 2) {
                        history.setDeviceInfo(parts[0]);
                        history.setLoginTime(new Date(Long.parseLong(parts[1])));
                    }
                    return history;
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取用户统计信息
     */
    public UserStatsDTO getUserStats(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        UserStatsDTO stats = new UserStatsDTO();
        stats.setUserId(userId);
        stats.setRegistrationDate(user.getCreatedAt());
        stats.setLastLoginDate(user.getLastLoginAt());
        stats.setEmailVerified(user.getEmailVerified());

        // 从Redis获取登录次数
        String logKey = "login:log:" + userId;
        Long loginCount = redisTemplate.opsForList().size(logKey);
        stats.setLoginCount(loginCount != null ? loginCount.intValue() : 0);

        // 其他统计信息可以根据业务需求添加

        return stats;
    }
}